package top.hcode.hoj.service.admin;

import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.sagacity.sqltoy.model.MapKit;
import org.sagacity.sqltoy.model.Page;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import top.hcode.hoj.common.LazyDao;
import top.hcode.hoj.dao.CollCreatedWorksScoreDao;
import top.hcode.hoj.dao.collect.CollCreatedWorksDao;
import top.hcode.hoj.mapper.FileMapper;
import top.hcode.hoj.pojo.dto.coll.QueryCollWorksDTO;
import top.hcode.hoj.pojo.dto.coll.QueryCollWorksStatDTO;
import top.hcode.hoj.pojo.entity.coll.CollCreatedWorks;
import top.hcode.hoj.pojo.entity.coll.CollCreatedWorksScore;
import top.hcode.hoj.pojo.entity.common.File;
import top.hcode.hoj.pojo.vo.coll.CollCreatedWorksStatVO;
import top.hcode.hoj.pojo.vo.coll.CollCreatedWorksVO;
import top.hcode.hoj.utils.PageUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author orangej
 * @since 2025-01-21
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class AdminCollCreatedWorksService {
    private final CollCreatedWorksDao collCreatedWorksDao;
    private final CollCreatedWorksScoreDao scoreDao;
    private final FileMapper fileMapper;
    private final LazyDao dao;
    private final StringRedisTemplate redisTemplate;

    public IPage<CollCreatedWorksVO> getCollCreatedWorksList(QueryCollWorksDTO form, List<String> schoolIdList) {
        Map<String, Object> params = Lang.obj2map(form);
        String classId = form.getClassId();
        if (Strings.isBlank(classId)) {
            // 未限制班级，使用学校列表
            params.put("schoolIdList", schoolIdList);
        }

        Page<CollCreatedWorksVO> pager = new Page<>(form.getLimit(), form.getCurrentPage());
        return PageUtil.toMybatis(dao.findPageBySql(pager, "queryWorksVOList", params, CollCreatedWorksVO.class));
    }

    public CollCreatedWorks getCollCreatedWorks(Long id) {
        return collCreatedWorksDao.getById(id);
    }

    public CollCreatedWorks saveCollCreatedWorks(CollCreatedWorks collCreatedWorks) {
        collCreatedWorksDao.saveOrUpdate(collCreatedWorks);
        return collCreatedWorks;
    }

    public void deleteCollCreatedWorks(Long id) {
        collCreatedWorksDao.removeById(id);
    }

    public CollCreatedWorksStatVO getStatInfo(QueryCollWorksStatDTO form, List<String> schoolIdList) {
        Map<String, Object> params = Lang.obj2map(form);
        String classId = form.getClassId();
        if (Strings.isBlank(classId)) {
            // 未限制班级，使用学校列表
            params.put("schoolIdList", schoolIdList);
        }

        // 查询作品统计信息
        List<NutMap> recordList = dao.findBySql("queryWorksStat", params, NutMap.class);
        CollCreatedWorksStatVO statVO = new CollCreatedWorksStatVO();
        for (NutMap record : recordList) {
            int judgeState = record.getInt("judgeState");
            if (judgeState == 1) {
                // 已评作品
                statVO.setAverageScore(record.getAs("avg", BigDecimal.class).setScale(2, RoundingMode.HALF_UP));
                statVO.setMaxScore(record.getAs("max", BigDecimal.class).setScale(2, RoundingMode.HALF_UP));
                statVO.setJudgeCount(record.getInt("count"));
            } else {
                // 未平作品
                statVO.setUnjudgeCount(record.getInt("count"));
            }
        }
        statVO.setTotalCount(statVO.getJudgeCount() + statVO.getUnjudgeCount());

        return statVO;
    }

    public CollCreatedWorksVO getCollCreatedWorksDetail(String id) {
        CollCreatedWorksVO vo = dao.loadBySql("queryWorksVOList", MapKit.map("id", id), CollCreatedWorksVO.class);
        loadAppendFileList(vo);
        return vo;
    }

    public CollCreatedWorksVO getCollCreatedWorksDetail(String userId, String collId) {
        CollCreatedWorksVO vo = dao.loadBySql("queryWorksVOList", MapKit.startOf("userId", userId).endOf("collId", collId),
                CollCreatedWorksVO.class);
        loadAppendFileList(vo);
        return vo;
    }

    void loadAppendFileList(CollCreatedWorksVO vo) {
        if (vo != null && Strings.isNotBlank(vo.getAppendFiles())) {
            String[] fileIds = vo.getAppendFiles().split(",");
            List<File> fileList = Arrays.stream(fileIds)
                    .map(id -> fileMapper.selectById(Long.parseLong(id)))
                    .filter(file -> file != null && !BooleanUtil.isTrue(file.getDelete()))
                    .collect(Collectors.toList());
            vo.setAppendFileList(fileList);
        }
    }

    /**
     * 给作品评分
     *
     * @param worksId 作品id
     * @param score   分数
     * @param uid     评分人
     */
    @Transactional
    public void judge(String worksId, BigDecimal score, String uid) {
        CollCreatedWorks works = collCreatedWorksDao.getById(worksId);
        if (works == null) {
            throw new IllegalArgumentException("作品不存在");
        }

        String judgeKey = "judge:works:" + worksId;
        try {
            if (BooleanUtil.isTrue(redisTemplate.hasKey(judgeKey))) {
                throw new IllegalArgumentException("该作品正在评分中，请稍后");
            }

            redisTemplate.opsForValue().set(judgeKey, "true", 15, TimeUnit.SECONDS);

            // 保存评分记录
            CollCreatedWorksScore scoreDbo = scoreDao.lambdaQuery().eq(CollCreatedWorksScore::getJudgeUid, uid)
                    .eq(CollCreatedWorksScore::getWorksId, worksId)
                    .one();
            if (scoreDbo != null) {
                scoreDbo.setScore(score);
            } else {
                scoreDbo = new CollCreatedWorksScore();
                scoreDbo.setWorksId(worksId);
                scoreDbo.setJudgeUid(uid);
            }
            scoreDbo.setScore(score);
            scoreDao.saveOrUpdate(scoreDbo);

            // 查询平均分和评分次数
            CollCreatedWorks record = dao.selectOne(CollCreatedWorks.class, "select works_id as id, " +
                    "count(1) as score_num, avg(score) as `score` from `coll_created_works_score` where `works_id` = ?", worksId);

            collCreatedWorksDao.updateById(record);
        } finally {
            redisTemplate.delete(judgeKey);
        }

    }
}
